{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "ac91513e",
   "metadata": {},
   "source": [
    "# 📢 MedReach\n",
    "**AI-Powered HCP Email Campaign System**\n",
    "\n",
    "---\n",
    "\n",
    "🧭 **System Overview**\n",
    "\n",
    "**MedReach** is an AI-powered multi-agent orchestration platform that automates personalized email campaigns to healthcare providers (HCPs) by intelligently selecting optimal messaging strategies and executing end-to-end campaign delivery.\n",
    "\n",
    "\n",
    "📝 **User Request:** \"Send a campaign about GlucoMax to endocrinologists in the Northeast regions\"\n",
    "\n",
    "\n",
    "🗂️ **Input Data**:\n",
    "\n",
    "```\n",
    "doctors.csv\n",
    "├── doctor_id: Unique identifier\n",
    "├── name: Healthcare provider full name\n",
    "├── email: Professional email address\n",
    "├── specialty: Medical specialty/practice area\n",
    "└── region: Geographic location\n",
    "```\n",
    "\n",
    "```\n",
    "doctors.csv\n",
    "-----------\n",
    "doctor_id,name,email,specialty,region\n",
    "1,Dr. Smith,smith@hospital.com,Endocrinology,Northeast\n",
    "2,Dr. Jones,jones@clinic.com,Cardiology,Southeast\n",
    "3,Dr. Brown,brown@medical.com,Endocrinology,West\n",
    "```\n",
    "\n",
    "🧩 **Multi-Agent Workflow Architecture**\n",
    "\n",
    "![](https://github.com/lisekarimi/agentverse/blob/main/assets/05_medreach-workflow.png?raw=true)\n",
    "\n",
    "\n",
    "\n",
    "📤 **Output Data**\n",
    "\n",
    "📊 **Campaign Tracking**\n",
    "\n",
    "```\n",
    "sent_emails.csv\n",
    "├── campaign_id: Unique campaign identifier\n",
    "├── doctor_id: Recipient identifier\n",
    "├── doctor_name: Recipient full name\n",
    "├── email_variant: Selected messaging strategy\n",
    "├── sent_at: Timestamp (ISO 8601)\n",
    "├── delivery_status: Success/failure indicator\n",
    "└── tracking_metadata: Additional performance metrics\n",
    "```\n",
    "\n",
    "```\n",
    "sent_emails.csv\n",
    "---------------\n",
    "campaign_id,doctor_id,doctor_name,email_variant,sent_at,status\n",
    "camp_001,1,Dr. Smith,roi_focused,2025-10-30 10:15:23,sent\n",
    "camp_001,3,Dr. Brown,roi_focused,2025-10-30 10:15:24,sent\n",
    "```\n",
    "\n",
    "🏗️ **Technical Architecture**\n",
    "\n",
    "- Agent Hierarchy\n",
    "    - **Orchestration Layer**: Campaign Manager Agent\n",
    "    - **Specialization Layer**: Content Writer Agents (Evidence/ROI/Safety)\n",
    "    - **Execution Layer**: Email Distribution Agent\n",
    "\n",
    "- Integration Points\n",
    "    - **Data Layer**: CSV file system\n",
    "    - **Messaging API**: Resend email service\n",
    "    - **AI Engine**: OpenAI GPT-4 model family\n",
    "\n",
    "- Design Patterns\n",
    "    - **Function Tools**: Direct Python code execution for data operations and API integrations\n",
    "    - **Agent-as-Tool**: Content writers return control to manager\n",
    "    - **Agent Handoff**: Distribution agent assumes full control post-selection\n",
    "\n",
    "---\n",
    "\n",
    "- 🌍 Task: AI-powered multi-agent system that automates personalized email campaigns to healthcare providers\n",
    "- 🧠 Model: GPT-4o-mini, Gemini 2.5 Flash, Llama 3.3 70B\n",
    "- 🎯 Process: Data Loading → Audience Filtering → Content Generation → Email Distribution\n",
    "- 📌 Output Format: Email, CSV tracking file with campaign metadata and sent email logs\n",
    "- 🔧 Tools: Resend API, CSV file operations, LLMs\n",
    "- 🧑‍💻 Skill Level: Intermediate\n",
    "\n",
    "🛠️ Requirements\n",
    "- ⚙️ Hardware: ✅ CPU is sufficient\n",
    "- External Services Required:\n",
    "    - Resend API (https://resend.com/) - Email delivery service for sending campaign emails\n",
    "    - OpenAI Platform (https://platform.openai.com/logs?api=traces) - For monitoring and tracking agent execution traces\n",
    "- API keys:\n",
    "    - 🔑 OpenAI API Key\n",
    "    - 🔑 OpenRouter API Key\n",
    "    - 🔑 Groq API Key\n",
    "    - 🔑 Resend API Key\n",
    "- 📧 Email address for testing\n",
    "- IPython environment (Jupyter/Colab)\n",
    "\n",
    "---\n",
    "📢 Discover more Agentic AI notebooks on my [GitHub repository](https://github.com/lisekarimi/agentverse) and explore additional AI projects on my [portfolio](https://lisekarimi.com).\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1bae9929",
   "metadata": {},
   "source": [
    "## 1. 🧰Imports and Environment Setup\n",
    "\n",
    "**Note:** You'll need to create a `.env` file in your project root with:\n",
    "\n",
    "```\n",
    "OPENAI_API_KEY=\n",
    "GROQ_API_KEY=\n",
    "OPENROUTER_API_KEY=\n",
    "RESEND_API_KEY=\n",
    "TO_EMAIL=your_email\n",
    "``` \n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "8783066f",
   "metadata": {},
   "outputs": [],
   "source": [
    "import os\n",
    "import pandas as pd\n",
    "import json\n",
    "import requests\n",
    "from pydantic import BaseModel\n",
    "from typing import List, Optional\n",
    "from dotenv import load_dotenv\n",
    "from agents import Agent, Runner, trace, function_tool, OpenAIChatCompletionsModel, input_guardrail, GuardrailFunctionOutput\n",
    "from openai import AsyncOpenAI"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "0b368587",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Load environment variables\n",
    "load_dotenv(override=True)\n",
    "\n",
    "#LLM\n",
    "groq_api_key = os.getenv('GROQ_API_KEY')\n",
    "openrouter_api_key = os.getenv('OPENROUTER_API_KEY')\n",
    "\n",
    "print(f\"   Groq API: {'✓ Configured' if groq_api_key else '✗ Missing'}\")\n",
    "print(f\"   OpenRouter API: {'✓ Configured' if openrouter_api_key else '✗ Missing'}\")\n",
    "\n",
    "# Setup Resend API key\n",
    "RESEND_API_KEY = os.getenv(\"RESEND_API_KEY\")\n",
    "TO_EMAIL = os.getenv(\"TO_EMAIL\")\n",
    "NAME = os.getenv(\"NAME\")\n",
    "\n",
    "print(f\"   Resend API: {'✓ Configured' if RESEND_API_KEY else '✗ Missing'}\")\n",
    "print(f\"   To Email: {'✓ Configured' if TO_EMAIL else '✗ Missing'}\")\n",
    "print(f\"   Name: {'✓ Configured' if NAME else '✗ Missing'}\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "00c282a4",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Constants\n",
    "file_path_input = 'data/input/doctors.csv'\n",
    "FROM_EMAIL= \"onboarding@resend.dev\" # default email for testing\n",
    "\n",
    "MODEL = \"gpt-4o-mini\"\n",
    "GROQ_MODEL = \"llama-3.3-70b-versatile\"\n",
    "OPENROUTER_MODEL = \"google/gemini-2.5-flash\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "3c1c6739",
   "metadata": {},
   "outputs": [],
   "source": [
    "# LLM\n",
    "GROQ_BASE_URL = \"https://api.groq.com/openai/v1\"\n",
    "OPENROUTER_BASE_URL = \"https://openrouter.ai/api/v1\"\n",
    "\n",
    "groq_client = AsyncOpenAI(base_url=GROQ_BASE_URL, api_key=groq_api_key)\n",
    "openrouter_client = AsyncOpenAI(base_url=OPENROUTER_BASE_URL, api_key=openrouter_api_key)\n",
    "\n",
    "llama3_3_model = OpenAIChatCompletionsModel(model=GROQ_MODEL, openai_client=groq_client)\n",
    "gemini_model = OpenAIChatCompletionsModel(model=OPENROUTER_MODEL, openai_client=openrouter_client)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "1fb0ff91",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Simple test - just one line\n",
    "response = await openrouter_client.chat.completions.create(model=OPENROUTER_MODEL, messages=[{\"role\": \"user\", \"content\": \"Say hello\"}])\n",
    "print(response.choices[0].message.content)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e8db83e3",
   "metadata": {},
   "source": [
    "## 2. 🏭Create Fake Data"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "bff957e2",
   "metadata": {},
   "outputs": [],
   "source": [
    "# ======================================\n",
    "# FAKE DATA FOR LEARNING PURPOSES ONLY\n",
    "# ======================================\n",
    "# This is sample data to demonstrate multi-agent systems.\n",
    "# In production, this would connect to a real HCP database.\n",
    "\n",
    "os.makedirs('data/input', exist_ok=True)\n",
    "os.makedirs('data/output', exist_ok=True)\n",
    "\n",
    "doctors_data = {\n",
    "    'doctor_id': [1, 2, 3, 4],\n",
    "    'name': [\n",
    "        'Dr. Sarah Johnson',\n",
    "        'Dr. Michael Chen',\n",
    "        NAME,\n",
    "        'Dr. James Williams'\n",
    "    ],\n",
    "    'email': [\n",
    "        'fake1@example.com',\n",
    "        'fake2@example.com',\n",
    "        TO_EMAIL,\n",
    "        'fake3@example.com'\n",
    "    ],\n",
    "    'specialty': [\n",
    "        'Endocrinology',\n",
    "        'Cardiology',\n",
    "        'Endocrinology',  # Will be selected ✅\n",
    "        'Orthopedics'\n",
    "    ],\n",
    "    'region': [\n",
    "        'Midwest',\n",
    "        'West',\n",
    "        'Northeast',  # Will be selected ✅\n",
    "        'Midwest'\n",
    "    ]\n",
    "}\n",
    "\n",
    "# Create DataFrame\n",
    "df = pd.DataFrame(doctors_data)\n",
    "\n",
    "# Save to CSV\n",
    "df.to_csv('data/input/doctors.csv', index=False)\n",
    "\n",
    "# Display results\n",
    "print(\"✅ doctors.csv created successfully!\")\n",
    "print(f\"   Total doctors: {len(df)}\")\n",
    "print(\"\\n⚠️  Note: Using fake data for educational demonstration\")\n",
    "print(\"\\n📋 Full Dataset:\")\n",
    "df.head()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7cbf1676",
   "metadata": {},
   "source": [
    "## 3. 🛠️Function Tools: Data Operations"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "d29388be",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Define the Doctor model\n",
    "class Doctor(BaseModel):\n",
    "    doctor_id: int\n",
    "    name: str\n",
    "    email: str\n",
    "    specialty: str\n",
    "    region: str"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "f67ac7c9",
   "metadata": {},
   "outputs": [],
   "source": [
    "@function_tool\n",
    "def read_csv(file_path_input: str):\n",
    "    \"\"\"Read doctor data from CSV file\"\"\"\n",
    "    df = pd.read_csv(file_path_input)\n",
    "    print(f\"✅ Loaded {len(df)} doctors from {file_path_input}\")\n",
    "    return df.to_dict('records')  # Return as list of dictionaries"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "96c43024",
   "metadata": {},
   "outputs": [],
   "source": [
    "@function_tool\n",
    "def filter_audience(doctors_list: List[Doctor], specialty: Optional[str] = None, region: Optional[str] = None):\n",
    "    \"\"\"Filter doctors by specialty and/or region\"\"\"\n",
    "    # Convert Pydantic models to dicts for DataFrame\n",
    "    doctors_dicts = [doc.model_dump() for doc in doctors_list]\n",
    "    df = pd.DataFrame(doctors_dicts)\n",
    "\n",
    "    if specialty:\n",
    "        df = df[df['specialty'] == specialty]\n",
    "    if region:\n",
    "        df = df[df['region'] == region]\n",
    "\n",
    "    print(f\"✅ Filtered to {len(df)} doctors\")\n",
    "    if specialty:\n",
    "        print(f\"   Specialty: {specialty}\")\n",
    "    if region:\n",
    "        print(f\"   Region: {region}\")\n",
    "\n",
    "    print(\"\\n📧 Emailing to:\")\n",
    "    for email in df['email'].tolist():\n",
    "        print(f\"   • {email}\")\n",
    "\n",
    "    return df.to_dict('records')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "539ae70d",
   "metadata": {},
   "outputs": [],
   "source": [
    "# ============================================\n",
    "# TEST THE FUNCTIONS\n",
    "# ============================================\n",
    "# Note: To test these functions directly, you must COMMENT OUT the @function_tool decorator\n",
    "# because @function_tool wraps functions for agent use only - they cannot be called directly by us.\n",
    "# After testing, UNCOMMENT @function_tool so agents can use them as tools.\n",
    "\n",
    "# print(\"📋 Testing data functions...\\n\")\n",
    "# doctors = read_csv('data/input/doctors.csv')\n",
    "# endocrinologists = filter_audience(doctors, specialty='Endocrinology', region='Northeast')\n",
    "\n",
    "# print(\"\\nFiltered result:\")\n",
    "# for doc in endocrinologists:\n",
    "#     print(f\"   • {doc['name']} - {doc['email']}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "59884360",
   "metadata": {},
   "source": [
    "## 4. ✍️Create Writer Agents (Agent-as-Tool Pattern)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "c836032f",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Shared formatting instructions for all writers\n",
    "WRITER_FORMAT_INSTRUCTIONS = f\"\"\"\n",
    "IMPORTANT FORMAT:\n",
    "- Start with a professional greeting (e.g., \"Dear Dr. [Last Name],\")\n",
    "- End with signature block:\n",
    "  Best regards,\n",
    "  GlucoMax Medical Affairs Team\n",
    "  Medical Science Liaison\n",
    "  GlucoMax Pharmaceuticals\n",
    "  {FROM_EMAIL} | +1-800-GLUCOMAX\n",
    "\n",
    "DO NOT add copyright notices, legal disclaimers, or footer text.\n",
    "Write complete, ready-to-send emails.\n",
    "\"\"\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "1cfe5805",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 1. Evidence-Based Writer Agent\n",
    "evidence_instructions = f\"\"\"\n",
    "You are a medical writer for GlucoMax Pharmaceuticals writing professional sales emails about GlucoMax, our diabetes medication.\n",
    "Focus on clinical evidence and scientific data.\n",
    "Emphasize clinical trial results, efficacy rates, and peer-reviewed research.\n",
    "Keep the tone professional and data-driven.\n",
    "\n",
    "{WRITER_FORMAT_INSTRUCTIONS}\n",
    "\"\"\"\n",
    "\n",
    "evidence_writer_agent = Agent(\n",
    "    name=\"Evidence-Based Writer\",\n",
    "    instructions=evidence_instructions,\n",
    "    model=MODEL\n",
    ")\n",
    "evidence_writer_agent"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "9238dfb7",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 2. ROI-Focused Writer Agent\n",
    "roi_instructions = f\"\"\"\n",
    "You are a medical writer for GlucoMax Pharmaceuticals writing sales emails about GlucoMax, our diabetes medication.\n",
    "Focus on cost-effectiveness and return on investment.\n",
    "Emphasize cost savings, patient outcomes that reduce healthcare spending, and economic benefits.\n",
    "Appeal to budget-conscious decision makers.\n",
    "\n",
    "{WRITER_FORMAT_INSTRUCTIONS}\n",
    "\"\"\"\n",
    "\n",
    "roi_writer_agent = Agent(\n",
    "    name=\"ROI-Focused Writer\",\n",
    "    instructions=roi_instructions,\n",
    "    model=gemini_model\n",
    "    # model=MODEL\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "38129fa1",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 3. Safety Profile Writer Agent\n",
    "safety_instructions = f\"\"\"\n",
    "You are a medical writer for GlucoMax Pharmaceuticals writing sales emails about GlucoMax, our diabetes medication.\n",
    "Focus on drug safety and tolerability.\n",
    "Emphasize low side effect profiles, long-term safety data, and patient comfort.\n",
    "Address common safety concerns proactively.\n",
    "\n",
    "{WRITER_FORMAT_INSTRUCTIONS}\n",
    "\"\"\"\n",
    "\n",
    "safety_writer_agent = Agent(\n",
    "    name=\"Safety Profile Writer\",\n",
    "    instructions=safety_instructions,\n",
    "    model=llama3_3_model\n",
    "    # model=MODEL\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "c0317662",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Convert agents to tools\n",
    "evidence_tool = evidence_writer_agent.as_tool(\n",
    "    tool_name=\"evidence_writer\",\n",
    "    tool_description=\"Write clinical evidence-focused sales email for healthcare providers\"\n",
    ")\n",
    "\n",
    "roi_tool = roi_writer_agent.as_tool(\n",
    "    tool_name=\"roi_writer\",\n",
    "    tool_description=\"Write cost-effectiveness focused sales email emphasizing ROI\"\n",
    ")\n",
    "\n",
    "safety_tool = safety_writer_agent.as_tool(\n",
    "    tool_name=\"safety_writer\",\n",
    "    tool_description=\"Write safety and tolerability focused sales email\"\n",
    ")\n",
    "\n",
    "# Gather all writer agent tools\n",
    "agent_writer_tools = [evidence_tool, roi_tool, safety_tool]\n",
    "\n",
    "agent_writer_tools"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4d3eab46",
   "metadata": {},
   "source": [
    "🤔 **Why Convert an Agent to a Tool?**\n",
    "\n",
    "- **The Problem:** The **Campaign Manager agent** needs a way to \"call\" or \"use\" the writer agents. But agents can't directly talk to other agents - they can only use **tools**.\n",
    "\n",
    "- **The Solution:**\n",
    "We wrap each writer agent inside a tool so the manager can use them like any other tool.\n",
    "\n",
    "---\n",
    "\n",
    "📞 **Think of it Like a Phone System:**\n",
    "\n",
    "**Without `.as_tool()`:**\n",
    "- Manager: \"I need to talk to the Evidence Writer\"\n",
    "- System: \"Sorry, you can only use tools, not talk to agents directly\"\n",
    "- Manager: \"But... I need their help!\"\n",
    "\n",
    "**With `.as_tool()`:**\n",
    "- Manager: \"I'll use the evidence_writer tool\"\n",
    "- Tool: *calls the Evidence Writer Agent internally*\n",
    "- Evidence Writer Agent: *writes the email*\n",
    "- Tool: *returns the email to Manager*\n",
    "- Manager: \"Perfect! Got the email.\"\n",
    "\n",
    "---\n",
    "\n",
    "🔧 **Technical Reason:**\n",
    "\n",
    "The `Agent` class has a `tools` parameter that only accepts **FunctionTool** objects:\n",
    "\n",
    "```python\n",
    "campaign_manager = Agent(\n",
    "    name=\"Manager\",\n",
    "    tools=[evidence_tool, roi_tool]  # ← Must be FunctionTools, not Agents!\n",
    ")\n",
    "```\n",
    "\n",
    "So we use `.as_tool()` to convert:\n",
    "- **Agent** → **FunctionTool** (that wraps the agent)\n",
    "\n",
    "---\n",
    "\n",
    "💡 **Summary:**\n",
    "\n",
    "- Agents can only use **tools** (not other agents directly)\n",
    "- `.as_tool()` wraps an agent so it becomes usable as a tool\n",
    "- The manager calls the tool → tool calls the agent → agent does work → returns result"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "106d66ec",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Combine function tools and agent tools\n",
    "all_tools = [read_csv, filter_audience] + agent_writer_tools\n",
    "all_tools"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cb50029f",
   "metadata": {},
   "source": [
    "## 5. 📨Email Formatting Agents"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "aab0ee0d",
   "metadata": {},
   "outputs": [],
   "source": [
    "subject_instructions = \"\"\"\n",
    "You write compelling subject lines for cold sales emails to healthcare providers.\n",
    "Create subjects that are professional, clear, and likely to get opened.\n",
    "Keep them concise (under 60 characters) and relevant to the email content.\n",
    "\"\"\"\n",
    "\n",
    "html_instructions = \"You can convert a text email body to an HTML email body. \\\n",
    "You are given a text email body which might have some markdown \\\n",
    "and you need to convert it to an HTML email body with simple, clear, compelling layout and design.\"\n",
    "\n",
    "subject_writer = Agent(\n",
    "    name=\"Email Subject Writer\",\n",
    "    instructions=subject_instructions,\n",
    "    model=MODEL\n",
    ")\n",
    "\n",
    "html_converter = Agent(\n",
    "    name=\"HTML Email Converter\",\n",
    "    instructions=html_instructions,\n",
    "    model=MODEL\n",
    ")\n",
    "\n",
    "# Convert to tools\n",
    "subject_tool = subject_writer.as_tool(\n",
    "    tool_name=\"subject_writer\",\n",
    "    tool_description=\"Write a compelling subject line for a sales email\"\n",
    ")\n",
    "\n",
    "html_tool = html_converter.as_tool(\n",
    "    tool_name=\"html_converter\",\n",
    "    tool_description=\"Convert text/markdown email body to professional HTML format\"\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "37dff3eb",
   "metadata": {},
   "outputs": [],
   "source": [
    "@function_tool\n",
    "def send_email(recipient_email: str, recipient_name: str, subject: str, html_body: str):\n",
    "    \"\"\"Send an email to a healthcare provider via Resend API\"\"\"\n",
    "\n",
    "    from_email = FROM_EMAIL\n",
    "\n",
    "    # Check for placeholders BEFORE sending\n",
    "    if '[' in html_body or ']' in html_body:\n",
    "        print(\"❌ ERROR: Email contains placeholders - not sending!\")\n",
    "        return {\"status\": \"failure\", \"message\": \"Email contains unreplaced placeholders\"}\n",
    "\n",
    "    headers = {\n",
    "        \"Authorization\": f\"Bearer {RESEND_API_KEY}\",\n",
    "        \"Content-Type\": \"application/json\"\n",
    "    }\n",
    "\n",
    "    # Send email\n",
    "    payload = {\n",
    "        \"from\": f\"GlucoMax Team <{from_email}>\",\n",
    "        \"to\": [recipient_email],\n",
    "        \"subject\": subject,\n",
    "        \"html\": html_body\n",
    "    }\n",
    "\n",
    "    response = requests.post(\"https://api.resend.com/emails\", json=payload, headers=headers)\n",
    "\n",
    "    print(f\"📧 Sending email to {recipient_name} ({recipient_email})...\")\n",
    "\n",
    "    if response.status_code == 200:\n",
    "        return {\"status\": \"success\", \"message\": f\"Email sent to {recipient_name}\"}\n",
    "    else:\n",
    "        return {\"status\": \"failure\", \"message\": response.text}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "bc8750a7",
   "metadata": {},
   "outputs": [],
   "source": [
    "@function_tool\n",
    "def log_to_csv(campaign_id: str, doctor_id: int, doctor_name: str, email_variant: str, status: str):\n",
    "    \"\"\"Log sent email to CSV for tracking\"\"\"\n",
    "\n",
    "    import datetime\n",
    "\n",
    "    timestamp = datetime.datetime.now().strftime(\"%Y%m%d_%H%M%S\")\n",
    "    file_path_output = f'data/output/sent_emails_{timestamp}.csv'\n",
    "\n",
    "    log_data = {\n",
    "        'campaign_id': [campaign_id],\n",
    "        'doctor_id': [doctor_id],\n",
    "        'doctor_name': [doctor_name],\n",
    "        'email_variant': [email_variant],\n",
    "        'sent_at': [datetime.datetime.now().isoformat()],\n",
    "        'status': [status]\n",
    "    }\n",
    "\n",
    "    df = pd.DataFrame(log_data)\n",
    "    df.to_csv(file_path_output, index=False)\n",
    "\n",
    "    print(f\"📝 Logging campaign data for {doctor_name} with status: {status}\")\n",
    "\n",
    "    return {\"status\": \"logged\", \"message\": f\"Campaign data logged to {file_path_output}\"}"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e0dd87c5",
   "metadata": {},
   "source": [
    "## 6. 📬Create Email Sender Agent"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "05687558",
   "metadata": {},
   "outputs": [],
   "source": [
    "email_sender_instructions = \"\"\"\n",
    "You are an email formatter and sender. You receive the body of an email to be sent.\n",
    "\n",
    "Step 1: Use the html_converter tool to convert the body to HTML and save the result.\n",
    "Step 2: Use the subject_writer tool to write a subject for the email and save the result.\n",
    "Step 3: Use the send_email tool with the HTML body from Step 1 and the subject from Step 2.\n",
    "\n",
    "IMPORTANT: Always pass the HTML output from html_converter to send_email, never the original text.\n",
    "\"\"\"\n",
    "\n",
    "# Email sender tools\n",
    "email_sender_tools = [html_tool, subject_tool, send_email, log_to_csv]\n",
    "\n",
    "email_sender_agent = Agent(\n",
    "    name=\"Email Sender\",\n",
    "    instructions=email_sender_instructions,\n",
    "    model=MODEL,\n",
    "    tools=email_sender_tools,\n",
    "    handoff_description=\"Format, send, and track emails to healthcare providers\"\n",
    ")\n",
    "\n",
    "print(\"✅ Email Sender Agent created\")\n",
    "print(email_sender_agent)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "d256eefe",
   "metadata": {},
   "outputs": [],
   "source": [
    "agent_dict = {\n",
    "    \"name\": email_sender_agent.name,\n",
    "    \"model\": email_sender_agent.model,\n",
    "    \"handoff_description\": email_sender_agent.handoff_description,\n",
    "    \"handoffs\": [handoff.name if hasattr(handoff, 'name') else str(handoff) for handoff in email_sender_agent.handoffs],\n",
    "    \"instructions\": email_sender_agent.instructions,\n",
    "    \"tools\": [\n",
    "        {\n",
    "            \"name\": tool.name,\n",
    "            \"description\": tool.description,\n",
    "            # \"params_json_schema\": tool.params_json_schema\n",
    "        }\n",
    "        for tool in email_sender_agent.tools\n",
    "    ]\n",
    "}\n",
    "\n",
    "print(\"✅ Email Sender Agent created\\n\")\n",
    "print(json.dumps(agent_dict, indent=2))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "65163086",
   "metadata": {},
   "source": [
    "## 7. 🛡️ Create Input Guardrail - Audience Validation"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "728d550f",
   "metadata": {},
   "outputs": [],
   "source": [
    "class CampaignRequestValidation(BaseModel):\n",
    "    has_specialty: bool\n",
    "    has_region: bool\n",
    "    is_valid_request: bool\n",
    "    missing_fields: List[str]\n",
    "\n",
    "request_validation_agent = Agent(\n",
    "    name=\"Campaign Request Validator\",\n",
    "    instructions=\"Check if the user's campaign request includes both a medical specialty and a geographic region. Both are required for valid campaigns.\",\n",
    "    output_type=CampaignRequestValidation,\n",
    "    model=MODEL\n",
    ")\n",
    "\n",
    "@input_guardrail\n",
    "async def validate_campaign_request(ctx, agent, message):\n",
    "    result = await Runner.run(request_validation_agent, message, context=ctx.context)\n",
    "    is_valid = result.final_output.is_valid_request\n",
    "    return GuardrailFunctionOutput(\n",
    "        output_info={\"validation\": result.final_output},\n",
    "        tripwire_triggered=not is_valid  # Block if invalid request\n",
    "    )"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "33aae605",
   "metadata": {},
   "source": [
    "## 8. 🧠Create the Campaign Manager Agent (Orchestrator)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "5e296250",
   "metadata": {},
   "outputs": [],
   "source": [
    "campaign_manager_instructions = f\"\"\"\n",
    "You are a pharmaceutical marketing campaign manager for GlucoMax, a new diabetes medication.\n",
    "\n",
    "You use the tools given to you to create targeted email campaigns for healthcare providers.\n",
    "You never generate emails yourself; you always use the writer tools.\n",
    "\n",
    "First, use read_csv to load doctors from '{file_path_input}'.\n",
    "Then use filter_audience to select doctors matching the user's criteria (specialty and region).\n",
    "You try all 3 writer agent tools to generate different email versions.\n",
    "You evaluate all 3 emails and explain your reasoning for which is most effective.\n",
    "You pick the single best email (and only the best email).\n",
    "After picking the best email, you handoff to the Email Sender Agent to format and send that one email.\n",
    "\"\"\"\n",
    "\n",
    "campaign_manager = Agent(\n",
    "    name=\"Campaign Manager\",\n",
    "    instructions=campaign_manager_instructions,\n",
    "    model=MODEL,\n",
    "    tools=all_tools,\n",
    "    handoffs=[email_sender_agent],\n",
    "    input_guardrails=[validate_campaign_request]\n",
    ")\n",
    "\n",
    "agent_dict = {\n",
    "    \"name\": campaign_manager.name,\n",
    "    \"model\": campaign_manager.model,\n",
    "    \"handoff_description\": campaign_manager.handoff_description,\n",
    "    \"handoffs\": [handoff.name if hasattr(handoff, 'name') else str(handoff) for handoff in campaign_manager.handoffs],\n",
    "    \"instructions\": campaign_manager.instructions,\n",
    "    \"tools\": [\n",
    "        {\n",
    "            \"name\": tool.name,\n",
    "            \"description\": tool.description,\n",
    "            # \"params_json_schema\": tool.params_json_schema\n",
    "        }\n",
    "        for tool in campaign_manager.tools\n",
    "    ]\n",
    "}\n",
    "\n",
    "print(\"✅ Campaign Manager Agent created\\n\")\n",
    "print(json.dumps(agent_dict, indent=2))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4c741729",
   "metadata": {},
   "source": [
    "## 9. 🚀Run the Multi-Agent Campaign System"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "f6c8478c",
   "metadata": {},
   "outputs": [],
   "source": [
    "# User request\n",
    "message = \"Send a campaign about GlucoMax to endocrinologists in the Northeast region\"\n",
    "\n",
    "print(\"Starting multi-agent campaign execution...\\n\")\n",
    "\n",
    "# Run with trace for visibility\n",
    "with trace(\"MedReach Campaign With Guardrails\"):\n",
    "    result = await Runner.run(campaign_manager, message)\n",
    "\n",
    "print(\"\\n\" + \"=\" * 60)\n",
    "print(\"✅ Campaign execution completed!\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "dfef4fc8",
   "metadata": {},
   "source": [
    "## 💡 Bonus: Function vs Agent Tools"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cae1a198",
   "metadata": {},
   "source": [
    "🎯 **When to Use Function Tools vs Agent Tools:**\n",
    "\n",
    " **Function Tools** (like `read_csv`, `filter_audience`)\n",
    "\n",
    "✅ Use when the task is **deterministic** and doesn't need AI reasoning:\n",
    "- Reading a file\n",
    "- Filtering data\n",
    "- Sending an email\n",
    "- Querying a database\n",
    "- Mathematical calculations\n",
    "\n",
    "**Why?** These are simple operations - just execute Python code. No need for expensive AI calls!\n",
    "\n",
    "---\n",
    "\n",
    "**Agent Tools** (like writer agents)\n",
    "\n",
    "✅ Use when the task needs **creativity, reasoning, or language generation**:\n",
    "- Writing emails\n",
    "- Analyzing complex data\n",
    "- Making strategic decisions\n",
    "- Creating content\n",
    "\n",
    "**Why?** These require AI intelligence - can't just write code for \"write a persuasive email\"!\n",
    "\n",
    "---\n",
    "\n",
    "💰 **Cost & Speed:**\n",
    "\n",
    "```python\n",
    "# Function tool - FREE & FAST\n",
    "read_csv('data.csv')  # Just Python, instant, $0\n",
    "\n",
    "# Agent tool - COSTS MONEY & SLOWER\n",
    "evidence_writer.write_email()  # AI API call, 2-3 seconds, costs tokens\n",
    "```\n",
    "\n",
    "---\n",
    "\n",
    "📋 **Rule of Thumb:**\n",
    "\n",
    "- **Can you write simple Python code for it?** → Function Tool\n",
    "- **Does it need AI to think/create?** → Agent Tool\n",
    "\n",
    "That's why we use function tools for data operations but agent tools for writing! 🎯"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": ".venv",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.12.11"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}